# -*- coding: utf-8 -*-
#
# This handles the game, using a huge Game class
#
#

import pygame
from pygame.locals import *
import sys, os

import default
import data
#import background
#import leveljakob as level
import level
import character
import popup
import sound

class Game:
    def __init__(self, screen, starting_level = 0):
        """Supplied screen on which to draw"""
        self.screen = screen

        self.camera = pygame.rect.Rect((0,0), self.screen.get_size())
        #self.background = background.Background('background.png')
        
        self.levelnr = starting_level
        self.lv = level.BasicLevel("city_" + str(self.levelnr) + ".lvl")

        #self.player = character.Player("badrobot.png", (0,0))
        
        self.setup_controls()

        self.lives = 4
        self.quit = False

        #self.quitwait = 10
        
    def really_quit(self):
        """Confirm quit event and exit the game"""
        if self.confirm(["Really quit?", "y/n"], True):
            sys.exit(0)
    def really_exit(self, key_press):
        """Confirm quit and exit to menu."""
        if self.confirm(["Really quit?", "y/n"], True):
            self.quit = True
    def check(self):
        """Checks and handles events according to the
        description in game.Game.setup_controls.
        We also check for events that are beyond the user's
        control."""

        for event in pygame.event.get():
            if event.type == QUIT:
                #We don't wanna quit without asking first. That's rude.
                self.really_quit()

            if event.type == KEYDOWN:
                for item in self.kb_controls.items():
                    #If we have a match in keys
                    if event.key == item[0]:
                        #We tell the according function that we pressed it
                        item[1](True)
            if event.type == KEYUP:
                for item in self.kb_controls.items():
                    #If we have a match in keys
                    if event.key == item[0]:
                        #We tell the according function that we released it
                        item[1](False)
            #if event.type == MOUSEBUTTONDOWN:
                ##We can only check individual buttons with pygame.mouse
                #pressed_buttons = pygame.mouse.get_pressed()
                #if pressed_buttons[0]:
                    #self.mouse_controls[0](True)
                #if pressed_buttons[1]:
                    #self.mouse_controls[1](True)
                #if pressed_buttons[2]:
                    #self.mouse_controls[2](True)
            #if event.type == MOUSEBUTTONUP:
                #pressed_buttons = pygame.mouse.get_pressed()
                #if pressed_buttons[0]:
                    #self.mouse_controls[0](False)
                #if pressed_buttons[1]:
                    #self.mouse_controls[1](False)
                #if pressed_buttons[2]:
                    #self.mouse_controls[2](False)


    def setup_controls(self):
        """Sets up a dictionary of key:function pairs.
        Every function should be simple, only handling
        things inside this class instance, and requiring
        only an argument saying if the key was pressed or
        released.
        We get a tuple for the mouse, and a dictionary for the
        keyboard, but the principle is the same."""
        self.kb_controls = { K_LEFT : self.lv.player.left,
                             K_RIGHT : self.lv.player.right,
                             K_SPACE : self.lv.player.jetpack,
                             K_ESCAPE : self.really_exit,
                             K_p : self.pause,
                             K_k : self.killall,
                             K_LCTRL : self.lv.player.attack
                             }
        #self.mouse_controls = (self.lv.player.left,
                               #self.lv.player.left,
                               #self.lv.player.left)

    def scroll(self, distance):
        """Scroll according to distance vector (tuple)"""
        self.camera.move_ip(distance)

    def check_collision(self):
        """Check collision between player and enemies,
        cannonballs and player,
        player bullets and enemies"""

        hits = pygame.sprite.groupcollide(self.lv.player_group,
                                          self.lv.enemy_group,
                                          False, False)
        

        for (player, enemies) in hits.items():

            for enemy in enemies:
                if player.killer and not enemy.dead:
                    #Die first, damage later
                    #Move him to a group where he can act alone
                    self.lv.dying_group.add(enemy)
                    self.lv.enemy_group.remove(enemy)
                    #Otherwise, we check if dying enemies are still living,
                    #which makes the game add a couple of seconds to the timer
                    #before ending the level

                    #Then he died...
                    enemy.die(self.lv)
                    enemy.change_animation("sawed")
                    player.change_animation("attacking")
                    
                    sound.play_sound("pluhe.wav")
                    sound.play_sound("chainsaw.wav")
                    
                elif enemy.killer:
                    player.die(self.lv)
                #the wimpy human dies!!!

        hits = pygame.sprite.groupcollide(self.lv.player_group,
                                          self.lv.damaging_group, False, True)
        
        for (player, cannonballs) in hits.items():
            player.dead = True

        if not self.lv.player.alive():
            self.lives -= 1
            if self.lives == 0:
                self.quit = True

        if self.lv.enemy_group.sprites() == []:
            self.level_cleared()

                
    def update_camera(self):
        self.camera.center = self.lv.player.world_pos.center
        #Check to see that the camera stays within level
        rect = self.lv.levelrect
        if self.camera.bottom > rect.bottom:
            self.camera.bottom = rect.bottom
        if self.camera.top < rect.top:
            self.camera.top = rect.top
        if self.camera.left < rect.left:
            self.camera.left = rect.left
        if self.camera.right > rect.right:
            self.camera.right = rect.right
     
    def pause(self, key_press):
        if key_press:
            self.confirm(["PAUSED"], False)

    def killall(self, randomarg = "bajs"):
             for enemy in self.lv.enemy_group.sprites():
                
                enemy.die(self.lv)


    def run(self):
        self.bg, rect = data.load_image("ingame_bg.png")
        
        self.clock = pygame.time.Clock()

        #play 10 frames before quitting
        while not self.quit:   #or self.quitwait < 10
            self.clock.tick(default.fps)
            
            self.check()

            #if self.quit:
            #    self.quitwait += 1
            
            #update leveltimer
            
            if self.lv.update_timer() <= 0 or self.lv.player.dead: #when the time runs out, print an encouraging message!
                self.confirm(["You fail"], False)
                #Go back to main menu 
                self.quit = True
                
            if self.lives <= 0:
                self.lv.player.dead = True
            
            #Update camera before characters
            self.update_camera()      

            ### Logic

            self.lv.player_group.update(self.camera, self.lv)
            self.lv.enemy_group.update(self.camera, self.lv)
            self.lv.dying_group.update(self.camera, self.lv)
            self.lv.effects_group.update(self.camera, self.lv)
            self.lv.cannon_group.update(self.camera, self.lv)
            self.lv.damaging_group.update(self.camera, self.lv)
            self.lv.player_bullets.update(self.camera, self.lv)

            self.check_collision()
            
            self.render()
            pygame.display.flip()
            
    def confirm(self, text, yes_no = False):
        """Render whole screen and wait for player confirmation"""
        answer = None
        
        message = popup.popup(text, (255, 255, 255), (20, 20, 20))
        
        rect = message.get_rect()
        screen_rect = self.screen.get_rect()

        message.set_alpha(200)
        
        while answer is None: 
            self.clock.tick(10) #save some cpu
            for event in pygame.event.get():
                #yes/no question
                if yes_no:
                    if event.type == QUIT:
                        answer = True
                        
                    if event.type == KEYDOWN:
                        if event.key == K_y:
                            answer = True
                        if event.key == K_n:
                            answer = False
                else:
                    #any key
                    if event.type == QUIT:
                        self.really_quit()
                    if event.type == KEYDOWN:
                        answer = 42

            #Render normally
            self.render()
            pos = (screen_rect.centerx - rect.w/2, screen_rect.centery - rect.h/2)
            self.screen.blit(message, pos)

            pygame.display.flip()

        return answer

    def render(self):
        """Render everything in the game (does not flip screen)"""
        ### Render
        self.screen.blit(self.bg, (0,0))
        self.lv.draw(self.camera, self.screen)
        self.lv.enemy_group.draw(self.screen)
        self.lv.dying_group.draw(self.screen)
        self.lv.effects_group.draw(self.screen) 
        self.lv.damaging_group.draw(self.screen)
        self.lv.cannon_group.draw(self.screen)
        self.lv.player_bullets.update(self.camera, self.lv)
        
        timerrect = self.lv.timer_image.get_rect()
        timerrect.center = (self.screen.get_rect().centerx, timerrect.h/2 + 5)
        self.screen.blit(self.lv.timer_image, timerrect)
        
        self.screen.blit(self.lv.player.jetmeter, (10, 10))
        self.lv.player_group.draw(self.screen)
        #self.playergroup.draw(self.screen) #WHAT?!
        
                    
    def level_cleared(self):
        self.confirm(["You destroyed City " + str(self.levelnr), "with " + str(self.lv.curr_time) + " seconds left to go", "Good job!", "", "Press any key to continue"], 
                     False)
        
        self.levelnr += 1
            
        #väldigt dåligt, eftersom samma kod används på flera ställen
        #den som orkar kan fixa centralt...
        if os.path.isfile(os.path.join(level.level_dir, "city_" + str(self.levelnr) + ".lvl")):
            self.lv = level.BasicLevel("city_" + str(self.levelnr) + ".lvl")
            try:
                file = open(os.path.join(data.data_dir, "unlocked"),"r")
                word = file.read().split()
            except IOError:
                file = open(os.path.join(data.data_dir, "unlocked"),"w")
                file.write("0\n")
                word = "0"
            
            file.close()

            file = file = open(os.path.join(data.data_dir, "unlocked"),"a")
            if not word.count(str(self.levelnr)): 
                file.write(str(self.levelnr) + "\n")        
            file.close()     
        else:
            self.confirm(["No more cities to destroy!", "", "You have cleared the game"], 
                     False)
            import credits
            credits.run(self.screen)
            self.quit = True
        self.playergroup = pygame.sprite.Group(self.lv.player)
        self.setup_controls() #required in order to move, perhaps
